home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / text / dtp / t1utils.lha / t1utils / t1asm.c < prev    next >
C/C++ Source or Header  |  1993-06-17  |  12KB  |  529 lines

  1. /* t1asm
  2. **
  3. ** This program `assembles' Adobe Type-1 font programs in pseudo-PostScript
  4. ** form into either PFB or PFA format.  The human readable/editable input is
  5. ** charstring- and eexec-encrypted as specified in the `Adobe Type 1 Font
  6. ** Format' version 1.1 (the `black book').  There is a companion program,
  7. ** t1disasm, which `disassembles' PFB and PFA files into a pseudo-PostScript
  8. ** file.
  9. **
  10. ** Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.
  11. **
  12. ** Permission is hereby granted to use, modify, and distribute this program
  13. ** for any purpose provided this copyright notice and the one below remain
  14. ** intact. 
  15. **
  16. ** author: I. Lee Hetherington (ilh@lcs.mit.edu)
  17. */
  18.  
  19. #ifndef lint
  20. static char sccsid[] =
  21.   "@(#) t1asm.c 1.2 10:09:46 5/22/92";
  22. static char copyright[] =
  23.   "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.";
  24. #endif
  25.  
  26. /* Note: this is ANSI C. */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32.  
  33. #ifdef MSDOS
  34. #define WB "wb"
  35. #else
  36. #define WB "w"
  37. #endif
  38.  
  39. #define BANNER   "This is t1asm 1.2.\n"
  40. #define LINESIZE 256
  41.  
  42. #define MAXBLOCKLEN ((1<<17)-6)
  43. #define MINBLOCKLEN ((1<<8)-6)
  44.  
  45. #define MARKER   128
  46. #define ASCII    1
  47. #define BINARY   2
  48. #define DONE     3
  49.  
  50. typedef unsigned char byte;
  51.  
  52. static FILE *ifp = stdin;
  53. static FILE *ofp = stdout;
  54.  
  55. /* flags */
  56. static int pfb = 0;
  57. static int active = 0;
  58. static int start_charstring = 0;
  59. static int in_eexec = 0;
  60.  
  61. static char line[LINESIZE];
  62.  
  63. /* lenIV and charstring start command */
  64. static int lenIV = 4;
  65. static char cs_start[10];
  66.  
  67. /* for charstring buffering */
  68. static byte charstring_buf[65535];
  69. static byte *charstring_bp;
  70.  
  71. /* for PFB block buffering */
  72. static byte blockbuf[MAXBLOCKLEN];
  73. static int blocklen = MAXBLOCKLEN;
  74. static int blockpos = -1;
  75. static int blocktyp = ASCII;
  76.  
  77. /* decryption stuff */
  78. static unsigned short er, cr;
  79. static unsigned short c1 = 52845, c2 = 22719;
  80.  
  81. /* table of charstring commands */
  82. static struct command {
  83.   char *name;
  84.   int one, two;
  85. } command_table[] = {
  86.   { "callothersubr", 12, 16 },
  87.   { "callsubr", 10, -1 },
  88.   { "closepath", 9, -1 },
  89.   { "div", 12, 12 },
  90.   { "dotsection", 12, 0 },
  91.   { "endchar", 14, -1 },
  92.   { "hlineto", 6, -1 },
  93.   { "hmoveto", 22, -1 },
  94.   { "hsbw", 13, -1 },
  95.   { "hstem", 1, -1 },
  96.   { "hstem3", 12, 2 },
  97.   { "hvcurveto", 31, -1 },
  98.   { "pop", 12, 17 },
  99.   { "return", 11, -1 },
  100.   { "rlineto", 5, -1 },
  101.   { "rmoveto", 21, -1 },
  102.   { "rrcurveto", 8, -1 },
  103.   { "sbw", 12, 7 },
  104.   { "seac", 12, 6 },
  105.   { "setcurrentpoint", 12, 33 },
  106.   { "vhcurveto", 30, -1 },
  107.   { "vlineto", 7, -1 },
  108.   { "vmoveto", 4, -1 },
  109.   { "vstem", 3, -1 },
  110.   { "vstem3", 12, 1 },
  111. };                          /* alphabetical */
  112.  
  113. /* Two separate decryption functions because eexec and charstring decryption 
  114.    must proceed in parallel. */
  115.  
  116. static byte eencrypt(byte plain)
  117. {
  118.   byte cipher;
  119.  
  120.   cipher = (plain ^ (er >> 8));
  121.   er = (cipher + er) * c1 + c2;
  122.   return cipher;
  123. }
  124.  
  125. static byte cencrypt(byte plain)
  126. {
  127.   byte cipher;
  128.  
  129.   cipher = (plain ^ (cr >> 8));
  130.   cr = (cipher + cr) * c1 + c2;
  131.   return cipher;
  132. }
  133.  
  134. /* This function flushes a buffered PFB block. */
  135.  
  136. static void output_block()
  137. {
  138.   int i;
  139.  
  140.   /* output four-byte block length */
  141.   fputc(blockpos & 0xff, ofp);
  142.   fputc((blockpos >> 8) & 0xff, ofp);
  143.   fputc((blockpos >> 16) & 0xff, ofp);
  144.   fputc((blockpos >> 24) & 0xff, ofp);
  145.  
  146.   /* output block data */
  147.   for (i = 0; i < blockpos; i++)
  148.     fputc(blockbuf[i], ofp);
  149.  
  150.   /* mark block buffer empty and uninitialized */
  151.   blockpos =  -1;
  152. }
  153.  
  154. /* This function outputs a single byte.  If output is in PFB format then output
  155.    is buffered through blockbuf[].  If output is in PFA format, then output
  156.    will be hexadecimal if in_eexec is set, ASCII otherwise. */
  157.  
  158. static void output_byte(byte b)
  159. {
  160.   static char *hexchar = "0123456789ABCDEF";
  161.   static int hexcol = 0;
  162.  
  163.   if (pfb) {
  164.     /* PFB */
  165.     if (blockpos < 0) {
  166.       fputc(MARKER, ofp);
  167.       fputc(blocktyp, ofp);
  168.       blockpos = 0;
  169.     }
  170.     blockbuf[blockpos++] = b;
  171.     if (blockpos == blocklen)
  172.       output_block();
  173.   } else {
  174.     /* PFA */
  175.     if (in_eexec) {
  176.       /* trim hexadecimal lines to 64 columns */
  177.       if (hexcol >= 64) {
  178.     fputc('\n', ofp);
  179.     hexcol = 0;
  180.       }
  181.       fputc(hexchar[(b >> 4) & 0xf], ofp);
  182.       fputc(hexchar[b & 0xf], ofp);
  183.       hexcol += 2;
  184.     } else {
  185.       fputc(b, ofp);
  186.     }
  187.   }
  188. }
  189.  
  190. /* This function outputs a byte through possible eexec encryption. */
  191.  
  192. static void eexec_byte(byte b)
  193. {
  194.   if (in_eexec)
  195.     output_byte(eencrypt(b));
  196.   else
  197.     output_byte(b);
  198. }
  199.  
  200. /* This function outputs a null-terminated string through possible eexec
  201.    encryption. */
  202.  
  203. static void eexec_string(char *string)
  204. {
  205.   while (*string)
  206.     eexec_byte((byte) *string++);
  207. }
  208.  
  209. /* This function gets ready for the eexec-encrypted data.  If output is in
  210.    PFB format then flush current ASCII block and get ready for binary block.
  211.    We start encryption with four random (zero) bytes. */
  212.  
  213. static void eexec_start()
  214. {
  215.   eexec_string(line);
  216.   if (pfb) {
  217.     output_block();
  218.     blocktyp = BINARY;
  219.   }
  220.  
  221.   in_eexec = 1;
  222.   er = 55665;
  223.   eexec_byte(0);
  224.   eexec_byte(0);
  225.   eexec_byte(0);
  226.   eexec_byte(0);
  227. }
  228.  
  229. /* This function wraps-up the eexec-encrypted data and writes ASCII trailer.
  230.    If output is in PFB format then this entails flushing binary block and
  231.    starting an ASCII block. */
  232.  
  233. static void eexec_end()
  234. {
  235.   int i, j;
  236.  
  237.   if (pfb) {
  238.     output_block();
  239.     blocktyp = ASCII;
  240.   } else {
  241.     fputc('\n', ofp);
  242.   }
  243.   in_eexec = 0;
  244.   for (i = 0; i < 7; i++) {
  245.     for (j = 0; j < 64; j++)
  246.       eexec_byte('0');
  247.     eexec_byte('\n');
  248.   }
  249.   eexec_string("cleartomark\n");
  250.   if (pfb) {
  251.     output_block();
  252.     fputc(MARKER, ofp);
  253.     fputc(DONE, ofp);
  254.   }
  255. }
  256.  
  257. /* This function returns an input line of characters.  A line is terminated by
  258.    length (including terminating null) greater than LINESIZE, a newline \n, or
  259.    when active (looking for charstrings) by '{'.  When terminated by a newline
  260.    the newline is put into line[].  When terminated by '{', the '{' is not put
  261.    into line[], and the flag start_charstring is set to 1. */
  262.  
  263. static void getline()
  264. {
  265.   int c;
  266.   char *p = line;
  267.   int comment = 0;
  268.  
  269.   start_charstring = 0;
  270.   while (p < line + LINESIZE) {
  271.     c = fgetc(ifp);
  272.     if (c == EOF)
  273.       break;
  274.     if (c == '%')
  275.       comment = 1;
  276.     if (active && !comment && c == '{') {
  277.       start_charstring = 1;
  278.       break;
  279.     }
  280.     *p++ = (char) c;
  281.     if (c == '\n')
  282.       break;
  283.   }
  284.   *p = '\0';
  285. }
  286.  
  287. /* This function is used by the binary search, bsearch(), for command names in
  288.    the command table. */
  289.  
  290. static int command_compare(const void *key, const void *item)
  291. {
  292.   return strcmp((char *) key, ((struct command *) item)->name);
  293. }
  294.  
  295. /* This function returns 1 if the string is an integer and 0 otherwise. */
  296.  
  297. static int is_integer(char *string)
  298. {
  299.   if (isdigit(string[0]) || string[0] == '-' || string[0] == '+') {
  300.     while (*++string && isdigit(*string))
  301.       ;                          /* deliberately empty */
  302.     if (!*string)
  303.       return 1;
  304.   }
  305.   return 0;
  306. }
  307.  
  308. /* This function initializes charstring encryption.  Note that this is called
  309.    at the beginning of every charstring. */
  310.  
  311. static void charstring_start()
  312. {
  313.   int i;
  314.  
  315.   charstring_bp = charstring_buf;
  316.   cr = 4330;
  317.   for (i = 0; i < lenIV; i++)
  318.     *charstring_bp++ = cencrypt((byte) 0);
  319. }
  320.  
  321. /* This function encrypts and buffers a single byte of charstring data. */
  322.  
  323. static void charstring_byte(v)
  324.   int v;
  325. {
  326.   byte b = ((unsigned int)v) & 0xff;
  327.  
  328.   if (charstring_bp - charstring_buf > sizeof(charstring_buf)) {
  329.     fprintf(stderr, "error: charstring_buf full (%d bytes)\n",
  330.         sizeof(charstring_buf));
  331.     exit(1);
  332.   }
  333.   *charstring_bp++ = cencrypt(b);
  334. }
  335.  
  336. /* This function outputs buffered, encrypted charstring data through possible
  337.    eexec encryption. */
  338.  
  339. static void charstring_end()
  340. {
  341.   byte *bp;
  342.  
  343.   sprintf(line, "%d %s ", charstring_bp - charstring_buf, cs_start);
  344.   eexec_string(line);
  345.   for (bp = charstring_buf; bp < charstring_bp; bp++)
  346.     eexec_byte(*bp);
  347. }
  348.  
  349. /* This function generates the charstring representation of an integer. */
  350.  
  351. static void charstring_int(int num)
  352. {
  353.   int x;
  354.  
  355.   if (num >= -107 && num <= 107) {
  356.     charstring_byte(num + 139);
  357.   } else if (num >= 108 && num <= 1131) {
  358.     x = num - 108;
  359.     charstring_byte(x / 256 + 247);
  360.     charstring_byte(x % 256);
  361.   } else if (num >= -1131 && num <= -108) {
  362.     x = abs(num) - 108;
  363.     charstring_byte(x / 256 + 251);
  364.     charstring_byte(x % 256);
  365.   } else if (num >= (-2147483647-1) && num <= 2147483647) {
  366.     charstring_byte(255);
  367.     charstring_byte(num >> 24);
  368.     charstring_byte(num >> 16);
  369.     charstring_byte(num >> 8);
  370.     charstring_byte(num);
  371.   } else {
  372.     fprintf(stderr,
  373.         "error: cannot format the integer %d, too large\n", num);
  374.     exit(1);
  375.   }
  376. }
  377.  
  378. /* This function parses an entire charstring into integers and commands,
  379.    outputting bytes through the charstring buffer. */
  380.  
  381. static void parse_charstring()
  382. {
  383.   struct command *cp;
  384.  
  385.   charstring_start();
  386.   while (fscanf(ifp, "%s", line) == 1) {
  387.     if (line[0] == '%') {
  388.       /* eat comment to end of line */
  389.       while (fgetc(ifp) != '\n' && !feof(ifp))
  390.     ;                      /* deliberately empty */
  391.       continue;
  392.     }
  393.     if (line[0] == '}')
  394.       break;
  395.     if (is_integer(line)) {
  396.       charstring_int(atoi(line));
  397.     } else {
  398.       cp = (struct command *)
  399.     bsearch((void *) line, (void *) command_table,
  400.         sizeof(command_table) / sizeof(struct command),
  401.         sizeof(struct command),
  402.         command_compare);
  403.       if (cp) {
  404.     charstring_byte(cp->one);
  405.     if (cp->two >= 0)
  406.       charstring_byte(cp->two);
  407.       } else {
  408.     fprintf(stderr, "error: cannot use `%s' in charstring\n");
  409.     exit(1);
  410.       }
  411.     }
  412.   }
  413.   charstring_end();
  414. }
  415.  
  416. static void usage()
  417. {
  418.   fprintf(stderr,
  419.       "usage: t1asm [-b] [-l block-length] [input [output]]\n");
  420.   fprintf(stderr,
  421.       "\n-b means output in PFB format, otherwise PFA format.\n");
  422.   fprintf(stderr,
  423.       "The block length applies to the length of blocks in the\n");
  424.   fprintf(stderr,
  425.       "PFB output file; the default is to use the largest possible.\n");
  426.   exit(1);
  427. }
  428.  
  429.  
  430. int main(int argc, char **argv)
  431. {
  432.   char *p, *q, *r;
  433.   int c;
  434.  
  435.   extern char *optarg;
  436.   extern int optind;
  437.   extern int getopt(int argc, char **argv, char *optstring);
  438.  
  439.   fprintf(stderr, "%s", BANNER);
  440.  
  441.   /* interpret command line arguments using getopt */
  442.   while ((c = getopt(argc, argv, "bl:")) != -1)
  443.     switch (c) {
  444.     case 'b':
  445.       pfb = 1;
  446.       break;
  447.     case 'l':
  448.       blocklen = atoi(optarg);
  449.       if (blocklen < MINBLOCKLEN) {
  450.     blocklen = MINBLOCKLEN;
  451.     fprintf(stderr,
  452.         "warning: using minimum block length of %d\n",
  453.         blocklen);
  454.       } else if (blocklen > MAXBLOCKLEN) {
  455.     blocklen = MAXBLOCKLEN;
  456.     fprintf(stderr,
  457.         "warning: using maximum block length of %d\n",
  458.         blocklen);
  459.       }
  460.       break;
  461.     default:
  462.       usage();
  463.       break;
  464.     }
  465.   if (argc - optind > 2)
  466.     usage();
  467.  
  468.   /* possibly open input & output files */
  469.   if (argc - optind >= 1) {
  470.     ifp = fopen(argv[optind], "r");
  471.     if (!ifp) {
  472.       fprintf(stderr, "error: cannot open %s for reading\n", argv[1]);
  473.       exit(1);
  474.     }
  475.   }
  476.   if (argc - optind >= 2) {
  477.     ofp = fopen(argv[optind + 1], WB);
  478.     if (!ofp) {
  479.       fprintf(stderr, "error: cannot open %s for writing\n", argv[2]);
  480.       exit(1);
  481.     }
  482.   }
  483.  
  484.   /* Finally, we loop until no more input.  Some special things to look for
  485.      are the `currentfile eexec' line, the beginning of the `/Subrs'
  486.      definition, the definition of `/lenIV', and the definition of the
  487.      charstring start command which has `...string currentfile...' in it. */
  488.  
  489.   while (!feof(ifp) && !ferror(ifp)) {
  490.     getline();
  491.     if (strcmp(line, "currentfile eexec\n") == 0) {
  492.       eexec_start();
  493.       continue;
  494.     } else if (strstr(line, "/Subrs") && isspace(line[6])) {
  495.       active = 1;
  496.     } else if ((p = strstr(line, "/lenIV"))) {
  497.       sscanf(p, "%*s %d", &lenIV);
  498.     } else if ((p = strstr(line, "string currentfile"))) {
  499.       /* locate the name of the charstring start command */
  500.       *p = '\0';                  /* damage line[] */
  501.       q = strrchr(line, '/');
  502.       if (q) {
  503.     r = cs_start;
  504.     ++q;
  505.     while (!isspace(*q) && *q != '{')
  506.       *r++ = *q++;
  507.     *r = '\0';
  508.       }
  509.       *p = 's';                      /* repair line[] */
  510.     }
  511.     /* output line data */
  512.     eexec_string(line);
  513.     if (start_charstring) {
  514.       if (!cs_start[0]) {
  515.     fprintf(stderr, "error: couldn't find charstring start command\n");
  516.     exit(1);
  517.       }
  518.       parse_charstring();
  519.     }
  520.   }
  521.   eexec_end();
  522.  
  523.   fclose(ifp);
  524.   fclose(ofp);
  525.  
  526.   return 0;
  527. }
  528.  
  529.